﻿using System;
using fastCSharp;
using fastCSharp.threading;
using System.Threading;

namespace OnlineJudge
{
    /// <summary>
    /// 测试计数
    /// </summary>
    class JudgeCount
    {
        /// <summary>
        /// OJ调用客户端
        /// </summary>
        public OnlineJudge.tcpClient.Server.tcpClient Client;
        /// <summary>
        /// OJ路由服务
        /// </summary>
        private RouterServer routerServer;
        /// <summary>
        /// OJ路由
        /// </summary>
        private Router router;
        /// <summary>
        /// 测试回调处理保持
        /// </summary>
        private fastCSharp.net.tcp.commandClient.streamCommandSocket.keepCallback onJudgeKeepCallback;
        /// <summary>
        /// 测试回调处理保持
        /// </summary>
        private fastCSharp.net.tcp.commandClient.streamCommandSocket.keepCallback onJudgeItemKeepCallback;
        /// <summary>
        /// OJ服务端口信息
        /// </summary>
        internal fastCSharp.net.tcp.host Host;
        /// <summary>
        /// 提交测试集合
        /// </summary>
        private subArray<JudgeReportBase> judges;
        /// <summary>
        /// OJ服务配置
        /// </summary>
        internal JudgePoolConfig Config;
        /// <summary>
        /// 提交测试集合访问锁
        /// </summary>
        private readonly object judgeLock = new object();
        /// <summary>
        /// 当前数量
        /// </summary>
        public int Count;
        /// <summary>
        /// 测试计数
        /// </summary>
        /// <param name="routerServer"></param>
        /// <param name="router"></param>
        /// <param name="client"></param>
        /// <param name="host"></param>
        public JudgeCount(RouterServer routerServer, Router router, OnlineJudge.tcpClient.Server.tcpClient client, fastCSharp.net.tcp.host host)
        {
            if (client != null && (Config = client.start()) != null)
            {
                onJudgeKeepCallback = client.onJudged(onJudged);
                onJudgeItemKeepCallback = client.onJudged(onItemJudged);
                Host = host;
                Count = -Config.JudgeCount;
                this.router = router;
                this.routerServer = routerServer;
                Client = client;
            }
        }
        /// <summary>
        /// 测试回调处理
        /// </summary>
        /// <param name="judgeReport"></param>
        private void onJudged(fastCSharp.net.returnValue<OnlineJudge.JudgeReportBase> judgeReport)
        {
            if (judgeReport.Type == fastCSharp.net.returnValue.type.Success)
            {
                routerServer.OnJudgeReports[(byte)judgeReport.Value.RouterCallback](judgeReport);
                if (judgeReport.Value.CompileType == CompileType.SpecialJudge || judgeReport.Value.State != JudgeState.Compiled)
                {
                    //Console.WriteLine("JudgeId[" + judgeReport.Value.JudgeId.toString() + "]");
                    router.OnJudged(this);
                }
            }
            else router.Error(this);
        }
        /// <summary>
        /// 测试回调处理
        /// </summary>
        /// <param name="judgeItem"></param>
        private void onItemJudged(fastCSharp.net.returnValue<OnlineJudge.JudgeItemBase> judgeItem)
        {
            //Console.WriteLine("JudgeId[" + judgeItem.Value.JudgeId.toString() + "] TestId[" + judgeItem.Value.TestId.toString() + "]");
            if (judgeItem.Type == fastCSharp.net.returnValue.type.Success) routerServer.OnJudgeItems[(byte)judgeItem.Value.RouterCallback](judgeItem);
        }
        /// <summary>
        /// 尝试增加测试数量
        /// </summary>
        public bool TryJudgeCount()
        {
            if (Count < 0)
            {
                ++Count;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 提交测试
        /// </summary>
        /// <param name="judge"></param>
        /// <returns></returns>
        public bool Judge(JudgeReportBase judge)
        {
            bool isJudge = false;
            try
            {
                isJudge = Client.judge(judge).Type == fastCSharp.net.returnValue.type.Success;
            }
            catch { }
            if (isJudge)
            {
                Monitor.Enter(judgeLock);
                try
                {
                    judges.Add(judge);
                }
                finally { Monitor.Exit(judgeLock); }
                return true;
            }
            router.Error(this);
            return false;
        }
        /// <summary>
        /// 错误处理
        /// </summary>
        public void Error()
        {
            Monitor.Enter(judgeLock);
            subArray<JudgeReportBase> judges = this.judges;
            this.judges.Null();
            Monitor.Exit(judgeLock); 
            routerServer.ErrorJudge(judges);
        }
    }
}
